<template>
  <!-- 预览报表 -->
  <div ref="reportRender" :class="['report-render', { pdf: isPdf }]">
    <div
      v-for="(element, index) in reportData.elementItems"
      :key="index"
      :class="['report-item', { layoutRow: element.options.layout === 'row' }]"
    >
      <component
        :is="element.renderComponentName"
        :element="element"
        :index="index"
        :Api="reportData.Api"
        :reportData="reportData"
        @copyPaper="copyPaper"
        @deletePaper="deletePaper"
      ></component>
    </div>
    <!-- <div class="modal-layer"></div> -->
  </div>
</template>

<script>
import {
  customInterface_get,
  customInterface_post,
  selectCustomReportByIds,
} from "@/api/ReportDesign/ReportDesign.js";
// import { getReportDetails } from "@/api/index.js";
import { RenderPaper } from "./components/index";
import Observer from "@/utils/eventBus.js";
import html2canvas from "html2canvas";
import jsPDF from "jspdf";
import { warning, success, errorInfo } from "@/utils/errorInfo";
import { getUUID } from "@/utils/index";
import * as _ from "lodash";
export default {
  name: "ReportRender",
  components: {
    RenderPaper,
  },
  data() {
    return {
      reportData: {},
      isPdf: false, // 是否是pdf功能
      once: true,
      PaperData: null, // 重要的变量，页面next加载循序
      isPaperLoad: false, // 增加延迟函数调用，预防table自动分页后出现BUG
      editReport: {
        id: null, // 编辑模块存储ID
        reportId: null, // 报表ID
        dictName: "", // 报表绑定字段type
        dataReturn: [], // 数据返回值
      },
    };
  },
  methods: {
    render(reportData) {
      // demo预览渲染 接口调用
      this.handleTestApi(reportData.Api)
        .then(() => {
          let deepData = _.cloneDeep(reportData) || {};
          if (deepData.reportOption.reportRenderingType === "lazy") {
            // 延迟加载
            let reportData_new = {
              ...deepData,
              elementItems: [],
            };
            this.reportData = reportData_new;
            this.PaperData = deepData.elementItems.entries();
            let value = this.PaperData.next();
            if (!value.done) {
              this.reportData.elementItems.push(value.value[1]);
              this.renderPaper(this.PaperData.next());
            }
          } else if (
            deepData.reportOption.reportRenderingType === "multipage"
          ) {
            // 多页面加载
            let api =
              deepData.Api.options.find(
                (apiItem) => apiItem.api === deepData.reportOption.api
              ) || null;
            if (api) {
              if (api.structure === "array") {
                // 必须为 Array类型才可以进行渲染
                let reportData_new = {
                  ...deepData,
                  elementItems: [],
                };
                for (let i = 0; i < api.data.length; i++) {
                  deepData.elementItems.forEach((item) => (item.apiIndex = i));
                  let deepElItem = _.cloneDeep(deepData.elementItems);
                  reportData_new.elementItems.push(...deepElItem);
                }
                this.reportData = reportData_new;
              } else {
                warning("检测到Api数据结构为Object，无法进行渲染页面");
              }
            } else {
              warning("无法查询到配置关联的API，无法进行渲染页面");
            }
          } else {
            this.reportData = deepData;
          }
        })
        .catch(() => {
          this.reportData = _.cloneDeep(reportData) || {};
        });
    },
    renderPaper(value) {
      if (value.done) {
        // 结束
        this.PaperData = null;
        this.$emit("rederOver");
      } else {
        this.$nextTick(() => {
          setTimeout(() => {
            this.reportData.elementItems.push(value.value[1]);
            this.renderPaper(this.PaperData.next());
          }, 100);
        });
      }
    },
    dataRender(reportData, params) {
      // 真实数据报表渲染
      if (this.once) {
        this.handleApi(reportData.Api, params)
          .then(() => {
            let deepData = _.cloneDeep(reportData) || {};
            this.once = false;
            if (deepData.reportOption.reportRenderingType === "lazy") {
              // 延迟加载
              let reportData_new = {
                ...deepData,
                elementItems: [],
              };
              this.reportData = reportData_new;
              this.PaperData = deepData.elementItems.entries();
              let value = this.PaperData.next();
              if (!value.done) {
                this.reportData.elementItems.push(value.value[1]);
                this.renderPaper(this.PaperData.next());
              }
            } else if (
              deepData.reportOption.reportRenderingType === "multipage"
            ) {
              // 多页面渲染
              let api =
                deepData.Api.options.find(
                  (apiItem) => apiItem.api === deepData.reportOption.api
                ) || null;
              if (api) {
                if (api.structure === "array") {
                  // 必须为 Array类型才可以进行渲染
                  let reportData_new = {
                    ...deepData,
                    elementItems: [],
                  };
                  for (let i = 0; i < api.data.length; i++) {
                    deepData.elementItems.forEach(
                      (item) => (item.apiIndex = i)
                    );
                    let deepElItem = _.cloneDeep(deepData.elementItems);
                    reportData_new.elementItems.push(...deepElItem);
                  }
                  this.reportData = reportData_new;
                } else {
                  warning("检测到Api数据结构为Object，无法进行渲染页面");
                }
              } else {
                warning("无法查询到配置关联的API，无法进行渲染页面");
              }
            } else {
              this.reportData = deepData;
            }
          })
          .catch(() => {
            warning("Api 地址调用失败，无法进行报表展示");
            this.once = true;
          });
      }
    },
    getPrintDom() {
      let dom = document.querySelector(".report-render");
      return dom;
    },
    print() {
      // 打印功能
      this.isPdf = true;
      return new Promise((resolve) => {
        let time = setTimeout(() => {
          let dom = document.querySelector(".report-render");
          this.generatePrint(dom).then((div) => {
            this.isPdf = false;
            div = null;
            resolve();
          });
          clearTimeout(time);
          time = null;
        }, 100);
      });
    },
    generatePrint(dom) {
      return new Promise((resolve, reject) => {
        let reportItem = dom.querySelectorAll(".report-item");
        let nextData = reportItem.entries();
        let div = document.createElement("div");
        const printPage = (value) => {
          // 生成打印的图片
          if (value.done) {
            // 结束
            this.$print(div);
            resolve(div);
          } else {
            html2canvas(value.value[1], {
              scale: 2,
              backgroundColor: "#ffffff",
              useCORS: true,
            }).then((canvas) => {
              const imgData = canvas.toDataURL("image/jpeg", 1.0);
              let img = document.createElement("img");
              img.classList.add("printImg");
              img.src = imgData;
              div.appendChild(img);
              printPage(nextData.next());
            });
          }
        };
        printPage(nextData.next());
      });
    },
    exportPDF() {
      this.isPdf = true;
      return new Promise((resolve) => {
        let time = setTimeout(() => {
          let dom = document.querySelector(".report-render");
          this.generatePDF(dom).then(() => {
            this.isPdf = false;
            resolve();
          });
          clearTimeout(time);
          time = null;
        }, 100);
      });
    },
    generatePDF(dom) {
      // 导出pdf功能
      return new Promise((resolve, reject) => {
        let reportItem = dom.querySelectorAll(".report-item");
        const pdf = new jsPDF("", "pt", "a4");
        let nextData = reportItem.entries();
        const pdfPage = (value) => {
          // 生成PDF
          if (value.done) {
            // 结束
            pdf.save(`${this.reportData.title}.pdf`);
            resolve();
          } else {
            html2canvas(value.value[1], {
              scale: 2,
              backgroundColor: "#ffffff",
              useCORS: true, // 是否尝试使用CORS从服务器加载图像 (allowTaint 允许跨域 不允许同时true)
            }).then((canvas) => {
              const contentWidth = canvas.width;
              const contentHeight = canvas.height;
              const imgWidth = 595.28;
              const imgHeight = (595.28 / contentWidth) * contentHeight;
              const pageData = canvas.toDataURL("image/jpeg", 1.0);
              pdf.addImage(pageData, "JPEG", 0, 0, imgWidth, imgHeight);
              if (value.value[0] !== reportItem.length - 1) pdf.addPage();
              pdfPage(nextData.next());
            });
          }
        };
        pdfPage(nextData.next());
      });
    },
    handleTestApi(api) {
      // 处理Test API
      return new Promise((resolve, reject) => {
        if (api && api.options.some((item) => item.disabled)) {
          // 有启动
          let p = [];
          api.options.forEach((item) => {
            if (item.disabled && item.api) {
              // 如果api有值才会进行数据调用
              p.push(this.customInterfaceText(item));
            } else console.error("未配置Api接口");
          });
          if (p.length > 0) {
            Promise.all(p)
              .then(() => {
                resolve();
              })
              .catch(() => {
                errorInfo("接口调用失败！");
                reject();
              });
          } else resolve();
        } else resolve(); // 无任何启动接口
      });
    },
    customInterfaceText(item) {
      // 自定义Test接口
      let { api, method, structure, params } = item;
      let param = {};
      params.forEach((item) => {
        if (item.disabled) param[item.field] = item.testData;
      });
      return new Promise((resolve, reject) => {
        if (method === "get") {
          customInterface_get(api, param).then((res) => {
            let resData = res?.data || null;
            if (resData) {
              if (structure === "object") {
                if (resData[0]) {
                  item.data = resData[0];
                  resolve();
                } else reject();
              } else if (structure === "array") {
                if (resData && Array.isArray(resData)) {
                  item.data = resData;
                  resolve();
                } else reject();
              }
            } else reject();
          });
        } else if (method === "post") {
          customInterface_post(api, param).then((res) => {
            let resData = res?.data || null;
            if (resData) {
              if (structure === "object") {
                if (resData[0]) {
                  item.data = resData[0];
                  resolve();
                } else reject();
              } else if (structure === "array") {
                if (resData && Array.isArray(resData)) {
                  item.data = resData;
                  resolve();
                } else reject();
              }
            } else reject();
          });
        }
      });
    },
    // 真实API、接口
    handleApi(api, params) {
      return new Promise((resolve, reject) => {
        if (api && api.options.some((item) => item.disabled)) {
          // 有启动
          let p = [];
          api.options.forEach((item) => {
            if (item.disabled && item.api) {
              // 如果api有值才会进行数据调用
              p.push(this.customInterface(item, params));
            } else console.error("未配置Api接口");
          });
          if (p.length > 0) {
            Promise.all(p)
              .then(() => {
                resolve();
              })
              .catch(() => {
                errorInfo("接口调用失败！");
                reject();
              });
          } else resolve();
        } else resolve(); // 无任何启动接口
      });
    },
    customInterface(item, paramsData) {
      // 自定义接口
      let { api, method, structure, params } = item;
      let param = {};
      params.forEach((item) => {
        if (item.disabled) param[item.field] = paramsData[item.field] || null;
      });
      return new Promise((resolve, reject) => {
        if (method === "get") {
          customInterface_get(api, param).then((res) => {
            let resData = res?.data || null;
            if (resData) {
              if (structure === "object") {
                if (resData[0]) {
                  item.data = resData[0];
                  resolve();
                } else {
                  reject();
                }
              } else if (structure === "array") {
                if (resData && Array.isArray(resData)) {
                  item.data = resData;
                  resolve();
                } else reject();
              }
            } else reject();
          });
        } else if (method === "post") {
          customInterface_post(api, param).then((res) => {
            let resData = res?.data || null;
            if (resData) {
              if (structure === "object") {
                if (resData[0]) {
                  item.data = resData[0];
                  resolve();
                } else reject();
              } else if (structure === "array") {
                if (resData && Array.isArray(resData)) {
                  item.data = resData;
                  resolve();
                } else reject();
              }
            } else reject();
          });
        }
      });
    },
    /**
     * 可编辑渲染器
     * @param {String} dictName 字典表绑定分组名称 或 存储B报表ID
     * @param {Object} params Api接口参数
     */
    editInit(dictName, params) {
      this.editReport.id = null; // 重制编辑ID
      this.editReport.dictName = dictName;
      const reg = /^[0-9]+$/; // 字符串是否为数字

      if (reg.test(dictName)) {
        // 渲染数据报表
        this.getReportDetails(dictName).then((data) => {
          this.editReport.id = dictName;
          this.editReport.reportId = data.reportId;
          this.editReport.dictType = data.dictType;
          // this.editReport.title
          this.dataRender(JSON.parse(data.jsonData), params);
        });
      } else {
        // 渲染基础模版报表
        this.getDicts(dictName).then((res) => {
          let data = res?.data || [];
          if (data && data.length > 0) {
            this.editReport.reportId = data[0].dictValue;
            selectCustomReportByIds([this.editReport.reportId]).then(
              (report) => {
                let reportData = report.data[0] || null;
                if (reportData)
                  this.dataRender(JSON.parse(reportData.content), params);
              }
            );
          }
        });
      }
      // 注册提取字段逻辑
      Observer.$off("dataReturnField");
      Observer.$on("dataReturnField", (data) => {
        if (this.editReport.dataReturn[data.index]) {
          this.editReport.dataReturn[data.index][data.field] = data.value;
        } else {
          this.editReport.dataReturn.push({
            [data.field]: data.value,
          });
        }
      });
    },
    /**
     * @returns 返回报表数据及某字段提取数据
     */
    editSave() {
      // 存储数据
      return {
        id: this.editReport.id,
        reportId: this.editReport.reportId,
        dictType: this.editReport.dictName,
        content: JSON.stringify(this.reportData),
        dataReturn: this.editReport.dataReturn,
      };
    },
    /**
     * 查询B报表的详情接口
     * @param {String} id B报表的ID值
     */
    getReportDetails(id) {
      return new Promise((resolve) => {
        getReportDetails({ id }).then((res) => {
          let data = res.data || {};
          if (data) resolve(data);
          else warning("渲染失败，数据异常");
        });
      });
    },
    /**
     * 编辑报表渲染器
     * @param {String} id B报表ID
     * @param {Object} params 接口参数
     */
    editDataRender(id, params) {
      // 可编辑视图渲染
      const reg = /^[0-9]+$/; // 字符串是否为数字
      if (reg.test(id)) {
        // 渲染数据报表
        this.getReportDetails(id).then((data) => {
          let reportData = JSON.parse(data.jsonData);
          reportData.previewOption.mode = "preview";
          this.dataRender(reportData, params);
        });
      } else {
        // 渲染基础模版报表
        this.getDicts(id).then((res) => {
          let data = res?.data || [];
          if (data && data.length > 0) {
            this.editReport.reportId = data[0].dictValue;
            selectCustomReportByIds([this.editReport.reportId]).then(
              (report) => {
                let reportData = report.data[0] || null;
                if (reportData) {
                  let jsonData = JSON.parse(reportData.content);
                  jsonData.previewOption.mode = "preview";
                  this.dataRender(jsonData, params);
                }
              }
            );
          }
        });
      }
    },
    copyPaper(index) {
      let deepData = _.cloneDeep(this.reportData.elementItems[index]);
      deepData.elementItems.forEach((item) => {
        item.id = getUUID();
        if (item.type === "layout") {
          // 递归复制
          if (item.optionData && item.optionData.length > 0) {
            item.optionData.forEach((c) => {
              c.elementItems.forEach((e) => {
                e.id = getUUID();
              });
            });
          } else if (item.columns && item.columns.length > 0) {
            item.columns.forEach((c) => {
              c.elementItems.forEach((e) => {
                e.id = getUUID();
              });
            });
          }
        }
      });
      let cloneData = {
        ...deepData,
        id: getUUID(),
      };
      this.reportData.elementItems.splice(index, 0, cloneData);
    },
    deletePaper(index) {
      this.reportData.elementItems.splice(index, 1);
    },
  },
  mounted() {
    this.$nextTick(() => {
      // 禁止右键菜单
      this.$refs.reportRender.oncontextmenu = function () {
        return false;
      };
    });
  },
};
</script>

<style>
@import url("./ReportRender.css");
@import url("../../font/font.css");
</style>